package com.nuoyuan.wx.wx.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.reflect.TypeToken;
import com.nuoyuan.wx.admin.controller.BookController;
import com.nuoyuan.wx.aop.NoLoginRequired;
import com.nuoyuan.wx.api.QueryUserTradeVo;
import com.nuoyuan.wx.common.constant.AuthcodeEnum;
import com.nuoyuan.wx.common.constant.AuthcodeTplConstant;
import com.nuoyuan.wx.common.constant.BookTypeEnum;
import com.nuoyuan.wx.common.constant.RedisConstant;
import com.nuoyuan.wx.common.controller.BaseController;
import com.nuoyuan.wx.common.dto.BaseRespDto;
import com.nuoyuan.wx.common.utils.*;
import com.nuoyuan.wx.dao.mapper.BookMapper;
import com.nuoyuan.wx.dao.mapper.UserMapper;
import com.nuoyuan.wx.dao.po.BookPo;
import com.nuoyuan.wx.dao.po.UserPo;
import com.nuoyuan.wx.service.ProductService;
import com.nuoyuan.wx.service.UserService;
import com.nuoyuan.wx.service.dto.TradeDto;
import com.nuoyuan.wx.service.helper.UserBeanHepler;
import com.nuoyuan.wx.service.respcode.AuthcodeRespCodeEnum;
import com.nuoyuan.wx.service.respcode.UserRespCodeEnum;
import com.nuoyuan.wx.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

/**
 * @Package com.nuoyuan.wx.wx.controller
 * @ClassName UserController
 * @Description TODO
 * @Author linus
 * @Date 2020-02-21 16:55
 * @Version 1.0
 **/
@RestController
public class UserController extends BaseController {
    public static final Logger log = LoggerFactory.getLogger(BookController.class);

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ProductService productService;
    @Autowired
    private BookMapper bookMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserService userService;

    /**
     * 注册
     * @param param
     * @param request
     * @param response
     * @return
     */
    @NoLoginRequired
    @RequestMapping(value = "/wx/user/register", method = RequestMethod.POST)
    @ResponseBody
    public String register(@RequestBody RegisterVo param, HttpServletRequest request, HttpServletResponse response) {
        try {
            if(param == null || org.apache.commons.lang3.StringUtils.isBlank(param.getIdNo())
                    || org.apache.commons.lang3.StringUtils.isBlank(param.getPassword())
                    || org.apache.commons.lang3.StringUtils.isBlank(param.getPhone())
                    || org.apache.commons.lang3.StringUtils.isBlank(param.getAuthcode())
                    || org.apache.commons.lang3.StringUtils.isBlank(param.getRealName())) {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp("输入的信息确实, 请确认。");
            }

            String idNoValidateResult = IdNoUtil.IdentityCardVerification(param.getIdNo().toLowerCase());
            if(!idNoValidateResult.equalsIgnoreCase("")) {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(idNoValidateResult);
            }

            //账户是否存在
            Wrapper<UserPo> queryWrapper = new QueryWrapper<>();
            ((QueryWrapper<UserPo>) queryWrapper).eq("id_no", param.getIdNo());
            UserPo existUser = userMapper.selectOne(queryWrapper);
            if (null != existUser) {
                log.error(UserRespCodeEnum.USER_EXIST.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(UserRespCodeEnum.USER_EXIST.getMsg());
            }

            //验证码是否失效
            Object redisAuthcode = redisUtil.get(RedisConstant.getWxAuthcodeKey(param.getPhone(), AuthcodeEnum.REGISTER.name()));
            if (null == redisAuthcode) {
                log.error(AuthcodeRespCodeEnum.EXPIRED.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(AuthcodeRespCodeEnum.EXPIRED.getMsg());
            }
            String authcode = redisAuthcode.toString();
            if (!param.getAuthcode().equalsIgnoreCase(authcode)) {
                log.error(AuthcodeRespCodeEnum.AUTHCODE_ERROR.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(AuthcodeRespCodeEnum.AUTHCODE_ERROR.getMsg());
            }
            redisUtil.del(RedisConstant.getWxAuthcodeKey(param.getPhone(), AuthcodeEnum.REGISTER.name()));

            //插入
            UserPo user = new UserPo();
            Date current = DateUtil.getCurrentTimestamp();
            user.setCreateTime(current);
            user.setUpdateTime(current);
            user.setIdNo(param.getIdNo());
            user.setPhone(param.getPhone());
            user.setPwd(param.getPassword());
            user.setRealName(param.getRealName());
            userMapper.insert(user);
            //token
            String token = this.buildToken(param.getIdNo(), param.getPassword());
            redisUtil.set(token, GsonUtil.toJson(user), RedisConstant.WX_LOGIN_EXPIRE_TIME);

            return GsonUtil.toJson(new TokenVo(token));
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }

    /**
     * 发送短信
     * @param param
     * @param request
     * @param response
     * @return
     */
    @NoLoginRequired
    @RequestMapping(value = "/wx/user/sms", method = RequestMethod.POST)
    @ResponseBody
    public String sms(@RequestBody SmsVo param, HttpServletRequest request, HttpServletResponse response) {
        try {
            //时效性
            String redisAuthcodeKey = RedisConstant.getWxAuthcodeKey(param.getPhone(), AuthcodeEnum.valueOf(param.getSmsType()).name());
            Object redisAuthcode = redisUtil.get(redisAuthcodeKey);
            if(null != redisAuthcode) {
                //禁止重复发送短信
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(AuthcodeRespCodeEnum.SEND_TWO_MANY.getMsg());
            }
            String authcode = AuthCodeUtil.getAuthCode(6);
            boolean sendRes = SmsUtil.sendSms(param.getPhone(), AuthcodeTplConstant.getContent(authcode, AuthcodeEnum.valueOf(param.getSmsType())),
                    DateUtil.formatTimestamp(DateUtil.getCurrentTimestamp(), DateUtil.FMT_DATE_YYYYMMDD_HHMMSS));
           if(sendRes) {
               redisUtil.set(redisAuthcodeKey, authcode, RedisConstant.AUTHCODE_EXPIRE_TIME);
               return this.buildSimpleSuccResp();
           }else {
               log.error(AuthcodeRespCodeEnum.SEND_FAIL.getMsg());
               response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
               return this.buildErrorResp(AuthcodeRespCodeEnum.SEND_FAIL.getMsg());
           }
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }


    /**
     * 登陆
     * @param param
     * @param request
     * @param response
     * @return
     */
    @NoLoginRequired
    @RequestMapping(value = "/wx/user/login", method = RequestMethod.POST)
    @ResponseBody
    public String login(@RequestBody RegisterVo param, HttpServletRequest request, HttpServletResponse response) {
        try {
            Wrapper<UserPo> queryWrapper = new QueryWrapper<>();
            ((QueryWrapper<UserPo>) queryWrapper).eq("id_no", param.getIdNo()).eq("pwd", param.getPassword());
            UserPo user = userMapper.selectOne(queryWrapper);
            if(null == user) {
                log.error(UserRespCodeEnum.LOGIN_NAME_PASS_NOT_MATCH.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(UserRespCodeEnum.LOGIN_NAME_PASS_NOT_MATCH.getMsg());
            }

            //token
            String token = this.buildToken(param.getIdNo(), param.getPassword());
            redisUtil.set(token, GsonUtil.toJson(user), RedisConstant.WX_LOGIN_EXPIRE_TIME);

            return GsonUtil.toJson(new TokenVo(token));
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }

    /**
     * 忘记密码
     * @param param
     * @param request
     * @param response
     * @return
     */
    @NoLoginRequired
    @RequestMapping(value = "/wx/user/forgetPwd", method = RequestMethod.POST)
    @ResponseBody
    public String forgetPwd(@RequestBody RegisterVo param, HttpServletRequest request, HttpServletResponse response) {
        try {
            //账户是否存在
            Wrapper<UserPo> queryWrapper = new QueryWrapper<>();
            ((QueryWrapper<UserPo>) queryWrapper).eq("id_no", param.getIdNo()).eq("phone", param.getPhone());
            UserPo existUser = userMapper.selectOne(queryWrapper);
            if (null == existUser) {
                log.error(UserRespCodeEnum.USER_NOT_EXIST.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(UserRespCodeEnum.USER_NOT_EXIST.getMsg());
            }

            //authcode validation
            //验证码是否失效
            String authcodeKey = RedisConstant.getWxAuthcodeKey(param.getPhone(), AuthcodeEnum.FORGETPWD.name());
            Object redisAuthcode = redisUtil.get(authcodeKey);
            if (null == redisAuthcode) {
                log.error(AuthcodeRespCodeEnum.EXPIRED.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(AuthcodeRespCodeEnum.EXPIRED.getMsg());
            }
            String authcode = redisAuthcode.toString();
            if (!param.getAuthcode().equalsIgnoreCase(authcode)) {
                log.error(AuthcodeRespCodeEnum.AUTHCODE_ERROR.getMsg());
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return this.buildErrorResp(AuthcodeRespCodeEnum.AUTHCODE_ERROR.getMsg());
            }
            redisUtil.del(authcodeKey);

            //update
            existUser.setPwd(param.getPassword());
            Wrapper<UserPo> updateWrapper = new UpdateWrapper<>();
            ((UpdateWrapper<UserPo>) updateWrapper).eq("id_no", param.getIdNo());
            userMapper.update(existUser, updateWrapper);
            return this.buildSimpleSuccResp();
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }


    /**
     * 查看个人信息
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/info", method = RequestMethod.GET)
    @ResponseBody
    public String userInfo(HttpServletRequest request, HttpServletResponse response) {
        try {
            UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
            Wrapper<UserPo> queryWrapper = new QueryWrapper<>();
            ((QueryWrapper<UserPo>) queryWrapper).eq("user_id", user.getUserId());
            UserPo po = userMapper.selectOne(queryWrapper);
            return GsonUtil.toJson(po);
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }

    /**
     * 产品收藏
     * @param param
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/collect", method = RequestMethod.POST)
    @ResponseBody
    public String collect(@RequestBody ProductVo param, HttpServletRequest request, HttpServletResponse response) {
       //product if exist
        BaseRespDto<ProductVo> resp = productService.getDetail(param);
        param = resp.getData();
        // redis add
        UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
        String userCollectKey = RedisConstant.getWxUserCollectKey(user.getUserId());
        Object collectsRedis = redisUtil.get(userCollectKey);

        if(null == collectsRedis) {
            List<ProductVo> products = new ArrayList<>();
            products.add(param);
            redisUtil.set(userCollectKey, GsonUtil.toJson(products));
        }else {
            List<ProductVo> products = GsonUtil.toList(collectsRedis.toString(), ProductVo.class);
            for(ProductVo p : products) {
                if(p.getProductId().equals(param.getProductId())) {
                    return this.buildSimpleSuccResp();
                }
            }
            products.add(param);
            redisUtil.set(userCollectKey, GsonUtil.toJson(products));
        }
        return this.buildSimpleSuccResp();
    }

    /**
     * 取消产品收藏
     * @param param
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/cancelCollect", method = RequestMethod.POST)
    @ResponseBody
    public String cancelCollect(@RequestBody ProductVo param, HttpServletRequest request, HttpServletResponse response) {
        //redis delete
        //product if exist
        BaseRespDto<ProductVo> resp = productService.getDetail(param);
        param = resp.getData();

        UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
        String userCollectKey = RedisConstant.getWxUserCollectKey(user.getUserId());
        Object collectsRedis = redisUtil.get(userCollectKey);
        if(null == collectsRedis) {
            return this.buildSimpleSuccResp();
        }

        List<ProductVo> products = GsonUtil.toList(collectsRedis.toString(), ProductVo.class);
        Iterator<ProductVo> iter = products.iterator();
        while(iter.hasNext()){
            ProductVo p = iter.next();
            if(p.getProductId().equals(param.getProductId())){
                iter.remove();
            }
        }
        if(CollectionUtils.isEmpty(products)) {
            redisUtil.del(userCollectKey);
        }else {
            redisUtil.set(userCollectKey, GsonUtil.toJson(products));
        }

        return this.buildSimpleSuccResp();
    }

    /**
     * 获取收藏列表
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/collections", method = RequestMethod.GET)
    @ResponseBody
    public String collections(HttpServletRequest request, HttpServletResponse response) {
        UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
        String userCollectKey = RedisConstant.getWxUserCollectKey(user.getUserId());
        Object collectsRedis = redisUtil.get(userCollectKey);
        if(null == collectsRedis) {
            PageVo page = new PageVo<>();
            page.setItems(new ArrayList());
            return GsonUtil.toJson(page);
        }

        PageVo page = new PageVo();
        List<ProductVo> products = GsonUtil.toList(collectsRedis.toString(), ProductVo.class);
        page.setCount(products.size());
        page.setItems(products);

        return GsonUtil.toJson(page);
    }

    /**
     * 获取投资列表
     * @param page
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/traders", method = RequestMethod.POST)
    @ResponseBody
    public String traders(@RequestBody PageVo page, HttpServletRequest request, HttpServletResponse response) {
        // redis TOKEN to user
        UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
        //rpc traders
        String url = "http://127.0.0.1:8080/trade/findTradeListByUser";
        Map<String, String> params = new HashMap<>();
        params.put("idNo", user.getIdNo());
        params.put("pageNo", String.valueOf(page.getPageNo()));
        params.put("pageSize", String.valueOf(page.getPageSize()));

        String result = HttpClientUtils.executePost(url, params);
        if(StringUtils.isEmpty(result)) {
            PageVo p = new PageVo<>();
            p.setItems(new ArrayList());
            return GsonUtil.toJson(p);
        }

        Type type = new TypeToken<PageVo<TradeDto>>() {}.getType();
        PageVo<TradeDto> tradePage = GsonUtil.fromJson(result, type);
        if(null == tradePage || CollectionUtils.isEmpty(tradePage.getItems())) {
            PageVo p = new PageVo<>();
            p.setItems(new ArrayList());
            return GsonUtil.toJson(p);
        }


        DecimalFormat decimalFormat =new DecimalFormat("#.00");
        List<BookVo> books = new ArrayList<>();
        List<TradeDto> trades = tradePage.getItems();
        for(TradeDto trade : trades) {
            BookVo vo = new BookVo();
            vo.setAnnualYield(decimalFormat.format(new BigDecimal(trade.getAnnualYield())) + "%");
            vo.setExpireationDate(trade.getExpirationDate());
            vo.setProductNo(trade.getProductNo());
            vo.setProductId(trade.getId());
            vo.setProductName(trade.getProductName());
            vo.setAppointmentAmount(trade.getAmount().divide(new BigDecimal("10000")));
            vo.setValueDate(trade.getValueDate());
            vo.setValueType(trade.getPaymentType() + "付息");
            vo.setIfTransfer(trade.getIfTransfer());
            books.add(vo);
        }

        page.setItems(books);
        page.setCount(tradePage.getCount());
        return GsonUtil.toJson(page);
    }


    /**
     * 获取预约/转让列表
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/books", method = RequestMethod.GET)
    @ResponseBody
    public String books(BookQueryVo query, HttpServletRequest request, HttpServletResponse response) {
        // redis TOKEN to user
        UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);
        //query books
        Wrapper<BookPo> queryWrapper = new QueryWrapper<>();
        ((QueryWrapper<BookPo>) queryWrapper).eq("user_id", user.getUserId()).eq("is_deleted", 0).eq("book_type", BookTypeEnum.valueOf(query.getBookType()).name()).orderByDesc("book_id");
        IPage p = new Page();
        p.setCurrent(query.getPageNo());
        p.setSize(query.getPageSize());
        IPage<BookPo> pages = bookMapper.selectPage(p, queryWrapper);

        if(null == pages || CollectionUtils.isEmpty(pages.getRecords())) {
            PageVo page = new PageVo<>();
            page.setItems(new ArrayList());
            return GsonUtil.toJson(page);
        }

        List<BookPo> books = pages.getRecords();

        List<BookVo> bookVos = new ArrayList<>();
        for(BookPo b : books) {
            BookVo vo = new BookVo();
            vo.setAnnualYield(b.getAnnualYield());
            vo.setExpireationMonth(b.getExpireationMonth());
            vo.setProductNo(b.getProductNo());
            vo.setProductName(b.getProductName());
            vo.setAppointmentAmount(b.getAppointmentAmount());
            vo.setStartAmount(b.getStartAmount());
            bookVos.add(vo);
        }

        PageVo<BookVo> page = new PageVo();
        page.setCount(pages.getTotal());
        page.setItems(bookVos);
        return GsonUtil.toJson(page);
    }



    /**
     * 更新用户风险等级
     * @param param
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/wx/user/risklevel", method = RequestMethod.POST)
    @ResponseBody
    public String updateRiskLevel(@RequestBody UserPo uv , HttpServletRequest request, HttpServletResponse response) {
        log.info("updateRiskLevel = {}", uv.getRiskLevel());
        try {
            UserPo user = GsonUtil.fromJson(redisUtil.get(getToken(request)).toString(), UserPo.class);

            log.info("user = {}", JSON.toJSONString(user));
            if(null == user) {
                return this.buildErrorResp("用户信息不存在");
            }

            user.setRiskLevel(uv.getRiskLevel());
            Wrapper<UserPo> updateWrapper = new UpdateWrapper<>();
            ((UpdateWrapper<UserPo>) updateWrapper).eq("user_id", user.getUserId());
            userMapper.update(user, updateWrapper);

            return this.buildSimpleSuccResp();
        } catch (Exception e) {
            log.error(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return this.buildErrorResp(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        }
    }

}
